package protocol;

import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.json.simple.JSONObject;

public class HTTPRequestHeaders extends HTTPPart {

	private String fMethod;
	private String fHTTPVersion;
	private Cookies fCookies;

	public Cookies getfCookies() {
		return fCookies;
	}

	public String getfMethod() {
		return fMethod;
	}

	public String getfURI() {
		return fURI;
	}

	private String fURI;

	public HTTPRequestHeaders(String msg) {
		super();
		fCookies = new Cookies();
		fMethod = null;
		fURI = null;
		fHTTPVersion = null;
		String resultString = msg.replaceAll("(?m)\r", "");
		this.fHeaders = this.parseHeader(resultString);
	}

	private String getHeaderName(final String header) {
		String resultString = null;
		Pattern regex = Pattern.compile("^([^:]+)", Pattern.MULTILINE);
		Matcher regexMatcher = regex.matcher(header);
		if (regexMatcher.find()) {
			resultString = regexMatcher.group(1);
		}
		return resultString;
	}

	private String getHeaderValue(final String header) {
		String resultString = null;
		Pattern regex = Pattern.compile("^[^:]+:\\s*(.*)", Pattern.MULTILINE);
		Matcher regexMatcher = regex.matcher(header);
		if (regexMatcher.find()) {
			resultString = regexMatcher.group(1);
		}
		return resultString;
	}

	private void parseTitle(String msg) {
		parseMethod(msg);
		parseURI(msg);
		parseHTTPVersion(msg);
	}

	private void parseMethod(String msg) {
		for (String method : Headers.ALLOWED_METHODS) {
			Pattern regex = Pattern.compile("\\A" + method);
			Matcher regexMatcher = regex.matcher(msg);
			if (regexMatcher.find()) {
				this.fMethod = regexMatcher.group();
			}
		}
	}

	private void parseURI(String msg) {
		Pattern regex = Pattern.compile("\\A[^\\s]+\\s*([^\\s]*)");

		Matcher regexMatcher = regex.matcher(msg);
		if (regexMatcher.find()) {
			this.fURI = regexMatcher.group(1);
		}
		fURI = fURI.replaceAll("^/", "");
	}

	private void parseHTTPVersion(String msg) {
		Pattern regex = Pattern.compile("\\A[^\\s]+\\s*[^\\s]+\\s+([^\\s]+)");
		Matcher regexMatcher = regex.matcher(msg);
		if (regexMatcher.find()) {
			this.fHTTPVersion = regexMatcher.group(1);
		}
	}

	@SuppressWarnings({ "unused", "unchecked" })
	private JSONObject commaDeliminatedHeader(String headerValue) {
		JSONObject retHeader = new JSONObject();
		String headerValueLineDeliminated = headerValue.replaceAll(
				"(?m)\\s*;\\s*", "\n");
		String[] headers = (headerValueLineDeliminated.split("\n"));
		for (String header : headers) {
			retHeader.put(getHeaderName(header), getHeaderValue(header));
		}
		return retHeader;
	}

	private String getHeaderFromMSG(final String data)
			throws PatternSyntaxException, RuntimeException {
		String regexResultString = null;
		String resultString = null;
		Pattern regex = Pattern.compile("^.*(\\r\\n\\r\\n|\\n\\n)",
				Pattern.DOTALL | Pattern.MULTILINE);
		Matcher regexMatcher = regex.matcher(data);
		if (regexMatcher.find()) {
			regexResultString = regexMatcher.group();
			resultString = regexResultString.replaceAll("(?sm)\n$", "");
			resultString = resultString.replaceAll("(?m)\r\r", "");
		}
		if (null == resultString) {
			resultString = data;
		}
		return resultString;
	}

	@SuppressWarnings("unchecked")
	private JSONObject parseHeader(final String msg)
			throws PatternSyntaxException {
		this.parseTitle(msg);
		String msgWithNoTitle = msg.replaceAll("(?m)\\A.*(\\r\\n|\\n)", "");
		String[] splittedHeaders = (getHeaderFromMSG(msgWithNoTitle))
				.split("\n");
		JSONObject retData = new JSONObject();
		for (String header : splittedHeaders) {
			retData.put(getHeaderName(header), getHeaderValue(header));
		}
		if (retData.containsKey(Headers.COOKIE)) {
			this.fCookies = new Cookies(retData.get(Headers.COOKIE).toString());
			retData.remove(Headers.COOKIE);
		}
		return retData;
	}

	public JSONObject getRequestHeaders() {
		return this.fHeaders;
	}

	@SuppressWarnings("rawtypes")
	public String toString() {
		String ret = new String();
		ret = this.fMethod + " " + this.fURI + " " + this.fHTTPVersion + "\n";
		for (Iterator iterator = this.fHeaders.keySet().iterator(); iterator
				.hasNext();) {
			String key = (String) iterator.next();
			if (!key.equals(Headers.COOKIE)) {
				ret += key + ": " + this.fHeaders.get(key) + "\n";
			}
		}
		if (this.fCookies.toString().length() > 2) {
			ret += Headers.COOKIE + ": " + this.fCookies.toString()+"\n";
		}
		return ret;
	}

	@Override
	public boolean isValid() {
		if (this.fURI == null || this.fURI.length() == 0) {
			return false;
		}
		if (this.fHTTPVersion == null || this.fHTTPVersion.length() == 0) {
			return false;
		}
		if (this.fMethod == null || this.fMethod.length() == 0) {
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	public JSONObject toJSONObject() {
		JSONObject ret = new JSONObject();
		if (this.isValid()) {
			ret.put(HTTP.HEADERS, this.fHeaders);
			ret.put(HTTP.METHOD, this.fMethod);
			ret.put(HTTP.URI, this.fURI);
			ret.put(HTTP.HTTP_VERSION, this.fHTTPVersion);
		}
		return ret;
	}
}
